﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Emgu.CV;
using Emgu.CV.Structure;
using System.Net;
using AxAXISMEDIACONTROLLib;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Drawing;

namespace CameraAPI
{
    class Camera
    {
        public static int w = 640; public static int h = 480;

        public Size dispSize = new Size(320, 240);
        public Size imgSize = new Size(320, 240);
       
        public static int nstate = 3;
        //public Image<Bgr, byte> curImg;
        public Image<Bgr, byte>[] bgImg = new Image<Bgr, byte>[nstate];
        public Calibration[] calibration = new Calibration[nstate];
        public String[] ptzCommand = new String[nstate];               
        
        public int curState = -1;
        public String cameraUrl = "";
        public AxAxisMediaControl cameraCtrl;
        public PictureBox pictureBox;

		byte[] bCS = new byte[w * h * 3 + 40];


        public Camera(String cameraUrl, AxAxisMediaControl cameraCtrl, String[] ptzCommand, int nstate,PictureBox pictureBox1)
        {
            this.cameraUrl = cameraUrl;
            this.cameraCtrl = cameraCtrl;
            this.ptzCommand = ptzCommand;
            this.pictureBox = pictureBox1;
            for (int i = 0; i < nstate; i++)
                calibration[i] = new Calibration();

            //this.nstate = nstate;
        }

		public byte[] getImageByte()
		{
			Object obj = new object();
			int theBufferSize;
			this.cameraCtrl.GetCurrentImage(1, out obj, out theBufferSize);
			bCS = ObjectToByteArray(obj);
			return bCS;
		}


        public Image<Bgr, byte> getImage()
        {
            int w,h;
            if (this.cameraCtrl.Name.Equals("camera2"))
            {
                w = 352; h = 288; //w = 704; h = 576; 
            }
            else
            {
                w = 320; h = 240; //w=640; h = 480;
            }
            byte[] b = new byte[w * h * 3 + 40];
            Object obj = new object();
            int ii;
            this.cameraCtrl.GetCurrentImage(1, out obj, out ii);
            b = ObjectToByteArray(obj);
            byte[, ,] image = new byte[h, w, 3];
            int k = (w * h * 3 + 40) + 37;// 921677;
            for (int i = 0; i < h; i++)
            {
                for (int j = 0; j < w; j++)
                {
                    image[i, (w - 1) - j, 0] = b[k--];
                    image[i, (w - 1) - j, 2] = b[k--];
                    image[i, (w - 1) - j, 1] = b[k--];

                }
            }

            Image<Bgr, byte> im = new Image<Bgr, byte>(image);
            
			//pictureBox1.Image = im.Bitmap;
            return im.Resize(Camera.w, Camera.h, Emgu.CV.CvEnum.INTER.CV_INTER_AREA);
        }

        public void PanTilt(String cameraUrl, String operation, String angle)
        {
            try
            {
                Uri address = new Uri("http://" + cameraUrl + "/axis-cgi/com/ptz.cgi?&" + operation + "=" + angle);
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(address);
                request.Credentials = new NetworkCredential("prabhu", "welcome");
                request.Method = "GET";
                request.KeepAlive = true;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                // MessageBox.Show(response.ToString());
                response.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.TargetSite + "  " + ex.Data + "  " + ex.GetBaseException() + "   " + ex.GetType() + "   " + ex.Message);
            }
        }

        public void PanTilt(int state)
        {   
            try
            {
                Uri address = new Uri("http://" + this.cameraUrl + "/axis-cgi/com/ptz.cgi?" + ptzCommand[state]);               //PTZ Command String: "http://172.26.187.74/axis-cgi/com/ptz.cgi?&pan=17.5474&tilt=-36.5500&zoom=2386"
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(address);
                request.Credentials = new NetworkCredential("root","welcome");
                request.Method = "GET";
                request.KeepAlive = true;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                response.Close();
                //MessageBox.Show(address + " " + request + " " + response);
                
                this.curState = state;
                
            }
            catch (Exception ex)
            {
                MessageBox.Show("Exception in PanTilt Operation in Camera : "+this.cameraUrl+" "+ex.Data);
            }
        }

        public void GotoHome(String state)
        {   
            try
            {   
                Uri address = new Uri("http://" + this.cameraUrl + "/axis-cgi/com/ptz.cgi?&" + "move" + "=" + "home");
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(address);
                request.Credentials = new NetworkCredential("root", "maslab");
                request.Method = "GET";
                request.KeepAlive = true;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                this.curState = 0;
                //MessageBox.Show(response.StatusCode);
                response.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.StackTrace);
            }
        }

        private string CompleteURL(string theMediaURL, string theMediaType)
        {
            string anURL = theMediaURL;
            if (!anURL.EndsWith("/")) anURL += "/";

            if (theMediaType == "mjpeg")
            {
                anURL += "axis-cgi/mjpg/video.cgi";
            }
            else if (theMediaType == "mpeg4")
            {
                anURL += "mpeg4/media.amp";
            }
            else if (theMediaType == "h264")
            {
                anURL += "axis-media/media.amp?videocodec=h264";
            }
            else if (theMediaType == "mpeg2-unicast")
            {
                anURL += "axis-cgi/mpeg2/video.cgi";
            }
            else if (theMediaType == "mpeg2-multicast")
            {
                anURL += "axis-cgi/mpeg2/video.cgi";
            }

            anURL = CompleteProtocol(anURL, theMediaType);
            return anURL;
        }

        private string CompleteProtocol(string theMediaURL, string theMediaType)
        {
            if (theMediaURL.IndexOf("://") >= 0) return theMediaURL;

            string anURL = theMediaURL;

            if (theMediaType == "mjpeg")
            {
                anURL = "http://" + anURL;
            }
            else if (theMediaType == "mpeg4" || theMediaType == "h264")
            {
                anURL = "axrtsphttp://" + anURL;
            }
            else if (theMediaType == "mpeg2-unicast")
            {
                anURL = "http://" + anURL;
            }
            else if (theMediaType == "mpeg2-multicast")
            {
                anURL = "axsdp" + anURL;
            }

            return anURL;
        }

        public void ConnectIpCam(AxAxisMediaControl camera, String userName, String password, String mediaType, String mediaUrl, bool isPlay)
        {
            camera.MediaUsername = userName;
            camera.MediaPassword = password;
            camera.MediaType = mediaType;
            camera.MediaURL = CompleteURL(mediaUrl, mediaType);
            // Start the streaming
            if (isPlay)
                camera.Play();
        }

        public void ConnectIpCam(String userName, String password, String mediaType, bool isPlay)
        {
            this.cameraCtrl.MediaUsername = userName;
            this.cameraCtrl.MediaPassword = password;
            this.cameraCtrl.MediaType = mediaType;
            this.cameraCtrl.MediaURL = CompleteURL(this.cameraUrl, mediaType);
            // Start the streaming
            if (isPlay)
                this.cameraCtrl.Play();
        }

        public byte[] ObjectToByteArray(object _Object)
        {
            try
            {
                // create new memory stream
                System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream();

                // create new BinaryFormatter
                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter _BinaryFormatter
                            = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

                // Serializes an object, or graph of connected objects, to the given stream.
                _BinaryFormatter.Serialize(_MemoryStream, _Object);

                // convert stream to byte array and return
                return _MemoryStream.ToArray();
            }
            catch (Exception _Exception)
            {
                // Error
                Console.WriteLine("Exception caught in process: {0}", _Exception.ToString());
            }

            // Error occured, return null
            return null;
        }

        public string GetCurrentPosition()
        {
            try
            {
                Uri address = new Uri("http://" + cameraUrl + "/axis-cgi/com/ptz.cgi?&query=position");
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(address);
                request.Credentials = new NetworkCredential("root", "welcome");
                request.Method = "GET";
                request.KeepAlive = true;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                /** Read the reply from server to get the position parameters**/
                // used to build entire input
                StringBuilder sb = new StringBuilder();
                // used on each read operation
                byte[] buf = new byte[8192];

                // we will read data via the response stream
                Stream resStream = response.GetResponseStream();
                string tempString = null;
                int count = 0;
                do
                {
                    // fill the buffer with data
                    count = resStream.Read(buf, 0, buf.Length);
                    // make sure we read some data
                    if (count != 0)
                    {
                        // translate from bytes to ASCII text
                        tempString = Encoding.ASCII.GetString(buf, 0, count);
                        // continue building the string
                        sb.Append(tempString);
                    }
                }
                while (count > 0); // any more data to read?
                String reply = sb.ToString();                
                string[] parameters = reply.Split('\n');
                string panAngle = parameters[0].Substring(4);
                // print out page source
                //MessageBox.Show(parameters[0].Substring(4));
                return reply;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.StackTrace);
                return null;
            }
        }

        public void TakeBackgroundImage()
        {
            for (int state = 0; state < nstate; state++)
            {
                this.PanTilt(state);
                //Thread.Sleep(500);
                this.bgImg[state] = getImage();
                this.pictureBox.Image = bgImg[state].Resize(dispSize.Width, dispSize.Height, Emgu.CV.CvEnum.INTER.CV_INTER_AREA).Bitmap;
                //WindowsFormsApplication1.Form1.ActiveForm.Update();
//                MessageBox.Show("TEST"); 
            }
           

        }

    }
}
